package com.vogue.api.common.rsa.advice;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import com.alibaba.fastjson.JSON;
import com.vogue.api.common.rsa.annotation.Encrypt;
import com.vogue.api.common.rsa.annotation.DecryptAndEncrypt;
import com.vogue.api.common.rsa.config.SecretKeyConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.HashMap;

/**
 * 响应结果加密
 */
@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    private boolean encrypt;

    @Autowired
    private SecretKeyConfig secretKeyConfig;

    private static ThreadLocal<Boolean> encryptLocal = new ThreadLocal<>();

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        encrypt = false;
        if ((returnType.getMethod().isAnnotationPresent(Encrypt.class) || returnType.getMethod().isAnnotationPresent(DecryptAndEncrypt.class)) && secretKeyConfig.isOpen()) {
            encrypt = true;
        }
        return encrypt;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        Boolean status = encryptLocal.get();
        if (null != status && !status) {
            encryptLocal.remove();
            return body;
        }

        if (encrypt) {
            try {
                //双向加密获取客户端的公钥
                String publicKey = secretKeyConfig.getClientPublicKey();
                if (!StringUtils.hasText(publicKey)) {
                    throw new NullPointerException("请配置publicKey秘钥 rsa.encrypt.publicKey");
                }
                HashMap<String,Object> map=new HashMap<>();
                map.put("noEncrypt",Boolean.TRUE.toString());

                RSA rsaDes = new RSA(null,secretKeyConfig.getClientPublicKey());
                String key = RandomUtil.randomString(16);
                String desKey = rsaDes.encryptBase64(key, KeyType.PublicKey);
                map.put("desKey",desKey);

                AES aes = new AES(Mode.ECB, Padding.PKCS5Padding, key.getBytes());

                String content = JSON.toJSONString(body);

                String data = aes.encryptBase64(content);
                map.put("data",data);

                if(secretKeyConfig.isShowLog()) {
                    log.info("待加密数据：{}，加密秘钥:{} ,加密后数据：{}", content,publicKey,data);
                }
                return map;
            } catch (Exception e) {
                log.error("加密异常", e);
            }
        }
        return body;
    }
}
